package service

import (
	"context"
	"crypto/md5"
	"crypto/sha1"
	"encoding/hex"
	"errors"
	"fmt"
	"gitee.com/go-caipu-team/go-caipu-plugin-sdk/pkg/utils"
	"go-caipu/pkg/setting"
	"io"
	"path/filepath"
	"time"

	"github.com/google/uuid"
	"gorm.io/gorm"

	"go-caipu/pkg/services/storage"
	"go-caipu/pkg/services/storage/models"
)

var (
	ErrGetStorageNotFound = errors.New("storage not found")
	//ErrGetStorageConfigFailed 获取存储配置失败
	ErrGetStorageConfigFailed = errors.New("get storage config failed")
)

// StorageService 上传服务
type StorageService struct {
	db  *gorm.DB
	cfg *setting.Cfg
}

// NewStorageService 创建上传服务实例
func NewStorageService(cfg *setting.Cfg, db *gorm.DB) *StorageService {
	return &StorageService{
		db:  db,
		cfg: cfg,
	}
}

// GetDefaultStorageConfig 获取默认存储配置
func (s *StorageService) GetDefaultStorageConfig() (*models.StorageConfig, error) {
	var config models.StorageConfig
	result := s.db.Where("is_default = ? AND status = ?", true, 1).First(&config)
	if result.Error != nil {
		return nil, result.Error
	}
	return &config, nil
}

// GetStorageConfigByType 获取指定类型的存储配置
func (s *StorageService) GetStorageConfigByType(storageType models.StorageType) (*models.StorageConfig, error) {
	var config models.StorageConfig
	result := s.db.Where("storage_type = ? AND status = ?", storageType, 1).
		Order("is_default DESC").
		First(&config)
	if result.Error != nil {
		return nil, result.Error
	}
	return &config, nil
}

// CreateStorageConfig 创建存储配置
func (s *StorageService) CreateStorageConfig(config *models.StorageConfig) error {
	// 如果设置为默认，需要将其他同类型的默认配置取消
	if config.IsDefault {
		tx := s.db.Begin()
		if err := tx.Model(&models.StorageConfig{}).
			Where("storage_type = ? AND is_default = ?", config.StorageType, true).
			Update("is_default", false).Error; err != nil {
			tx.Rollback()
			return err
		}

		if err := tx.Create(config).Error; err != nil {
			tx.Rollback()
			return err
		}

		return tx.Commit().Error
	}

	return s.db.Create(config).Error
}

// UpdateStorageConfig 更新存储配置
func (s *StorageService) UpdateStorageConfig(config *models.StorageConfig) error {
	// 如果设置为默认，需要将其他同类型的默认配置取消
	if config.IsDefault {
		tx := s.db.Begin()
		if err := tx.Model(&models.StorageConfig{}).
			Where("storage_type = ? AND is_default = ? AND id != ?", config.StorageType, true, config.ID).
			Update("is_default", false).Error; err != nil {
			tx.Rollback()
			return err
		}

		if err := tx.Save(config).Error; err != nil {
			tx.Rollback()
			return err
		}

		return tx.Commit().Error
	}

	return s.db.Save(config).Error
}

// ListStorageConfigs 获取存储配置列表
func (s *StorageService) ListStorageConfigs(storageType models.StorageType, name string) ([]models.StorageConfig, error) {
	var configs []models.StorageConfig
	query := s.db.Model(&models.StorageConfig{})
	if storageType != "" {
		query = query.Where("type = ?", storageType)
	}
	if name != "" {
		query = query.Where("config_name LIKE ?", "%"+name+"%")
	}
	if err := query.Find(&configs).Error; err != nil {
		return nil, err
	}
	return configs, nil
}

// GetStorageConfig 获得存储配置
func (s *StorageService) GetStorageConfig(id int64) (*models.StorageConfig, error) {
	var config models.StorageConfig
	result := s.db.Where("id = ?", id).First(&config)
	if result.Error != nil {
		return nil, result.Error
	}
	return &config, nil
}
func (s *StorageService) UpdateStatus(id int64, status int8) error {
	//更新配置状态到数据库
	config := &models.StorageConfig{}
	result := s.db.Where("id = ?", id).First(config)
	if result.Error != nil {
		return result.Error
	}
	config.Status = status
	if err := s.db.Save(config).Error; err != nil {
		return err
	}
	return nil
}

// SetDefaultStorageConfig 设置默认存储配置
func (s *StorageService) SetDefaultStorageConfig(id int64) error {
	// 开启事务
	return s.db.Transaction(func(tx *gorm.DB) error {
		// 先取消所有默认设置
		if err := tx.Model(&models.StorageConfig{}).
			Where("is_default = ?", true).
			Update("is_default", false).Error; err != nil {
			return err
		}

		// 设置新的默认存储
		if err := tx.Model(&models.StorageConfig{}).
			Where("id = ?", id).
			Update("is_default", true).Error; err != nil {
			return err
		}
		return nil
	})
}

// DeleteStorageConfig 删除存储配置
func (s *StorageService) DeleteStorageConfig(ids []int64) error {
	return s.db.Delete(&models.StorageConfig{}, ids).Error
}
func (s *StorageService) Upload(ctx context.Context, file *models.FileStorage, reader io.Reader) error {
	// 获取存储配置
	store, config, err := s.initStorage(file.StorageType)
	if err != nil {
		return err
	}
	// 生成唯一fileKey
	file.FileExt = filepath.Ext(file.FileName)
	file.FileKey = fmt.Sprintf("%s%s", uuid.New().String(), file.FileExt)

	// 可以根据日期创建存储路径
	file.StoragePath = time.Now().Format("2006/01/02")
	// 使用配置中的默认bucket
	file.BucketName = config.BucketName
	file.StorageType = config.StorageType

	// 计算文件的MD5和SHA1
	md5Hash := md5.New()
	sha1Hash := sha1.New()
	multiWriter := io.MultiWriter(md5Hash, sha1Hash)
	// 复制文件内容，同时计算哈希
	if _, err := io.Copy(multiWriter, reader); err != nil {
		return fmt.Errorf("failed to copy file content: %v", err)
	}
	file.MD5 = hex.EncodeToString(md5Hash.Sum(nil))
	file.SHA1 = hex.EncodeToString(sha1Hash.Sum(nil))

	// 检查 reader 是否支持 Seek（如 *os.File, *bytes.Reader）
	if seeker, ok := reader.(io.Seeker); ok {
		// 重置到文件开头
		if _, err := seeker.Seek(0, io.SeekStart); err != nil {
			return fmt.Errorf("failed to seek reader: %v", err)
		}
	}

	// 上传文件
	fileStorage, err := store.Upload(ctx, reader, file)
	if err != nil {
		return fmt.Errorf("上传文件失败: %v", err)
	}

	// 保存到数据库
	if err := s.db.Create(fileStorage).Error; err != nil {
		// 上传失败，删除已上传的文件
		store.Delete(ctx, file.FileKey, config.BucketName)
		return fmt.Errorf("保存文件信息失败: %v", err)
	}
	return nil
}

// GetFileInfo 获取文件信息
func (s *StorageService) GetFileInfo(fileKey string) (*models.FileStorage, error) {
	var fileStorage models.FileStorage
	result := s.db.Where("file_key = ? AND status = ?", fileKey, 1).First(&fileStorage)
	if result.Error != nil {
		return nil, result.Error
	}
	return &fileStorage, nil
}

// initStorage 初始化存储
func (s *StorageService) initStorage(storageType models.StorageType) (storage.Storage, *models.StorageConfig, error) {
	// 获取存储配置
	var config *models.StorageConfig
	var err error

	if storageType == "" {
		// 使用默认存储
		config, err = s.GetDefaultStorageConfig()
	} else {
		// 使用指定存储
		config, err = s.GetStorageConfigByType(storageType)
	}
	//解密密钥
	encrypt := utils.New(s.cfg.Application.EncryptionKey)
	secretKey, _ := encrypt.Decrypt(config.SecretKey) //加密后的数据
	config.SecretKey = secretKey
	if err != nil {
		return nil, nil, fmt.Errorf("获取存储配置失败: %v", err)
	}

	// 创建存储实例
	store, err := storage.NewStorage(config.StorageType)
	if err != nil {
		return nil, nil, fmt.Errorf("创建存储实例失败: %v", err)
	}

	// 初始化存储
	if err := store.Init(*config); err != nil {
		return nil, nil, fmt.Errorf("初始化存储失败: %v", err)
	}
	return store, config, nil
}

// DownLoad 获取文件内容
func (s *StorageService) DownLoad(ctx context.Context, fileKey string) (io.ReadCloser, *models.FileStorage, error) {
	// 获取存储配置
	file, err := s.GetFileInfo(fileKey)
	if err != nil {
		return nil, nil, err
	}
	store, _, err := s.initStorage(file.StorageType)
	if err != nil {
		return nil, file, err
	}

	content, err := store.Download(ctx, file.StoragePath, fileKey)
	if err != nil {
		return nil, file, fmt.Errorf("下载文件失败: %v", err)
	}
	return content, file, nil
}

// GetFileUrl 获取文件内容
func (s *StorageService) GetFileUrl(ctx context.Context, fileKey string) (string, error) {
	// 获取存储配置
	file, err := s.GetFileInfo(fileKey)
	if err != nil {
		return "", err
	}
	store, _, err := s.initStorage(file.StorageType)
	if err != nil {
		return "", err
	}

	content, err := store.GetFileURL(ctx, file.StoragePath, fileKey)
	if err != nil {
		return "", fmt.Errorf("Get file url error: %v", err)
	}
	return content, nil
}

// DeleteFile 删除文件
func (s *StorageService) DeleteFile(ctx context.Context, fileKey string) error {
	// 获取文件信息
	fileStorage, err := s.GetFileInfo(fileKey)
	if err != nil {
		return fmt.Errorf("获取文件信息失败: %v", err)
	}

	store, _, err := s.initStorage(fileStorage.StorageType)
	if err != nil {
		return err
	}

	// 删除存储中的文件
	if err := store.Delete(ctx, fileStorage.StoragePath, fileKey); err != nil {
		return fmt.Errorf("删除文件失败: %v", err)
	}

	// 更新文件状态为删除
	if err := s.db.Model(&fileStorage).Where("id", fileStorage.ID).Update("status", 0).Error; err != nil {
		return fmt.Errorf("更新文件状态失败: %v", err)
	}

	return nil
}
